﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using BOMS.Lib.Net;
using System.Net;
using BOMS.TcpClientSimulator;
using System.Threading;
using TcpclientSimulator.TcpFunc;
using BOMS.TcpClientSimulator.ThreadPool;
using System.Xml;
using System.Configuration;


namespace BOMS.TcpClientSimulator
{
    public partial class FormTcpClientSimulator : Form
    {

       // protected delegate void ClientConnectServerHandler(CliSocketParam cliSocketParam);


        BomsThreadPool ThreadPool = new BomsThreadPool(10);
        XmlDocument _xDocCfg=null;
        XmlDocument xDocCfg
        {
            get{
                if(_xDocCfg ==null)
                    _xDocCfg = Data.GetDataConfigXmlDoc();
                return _xDocCfg;
            }            
        }
        bool ShowWinMessage = false; // bool.Parse(ConfigurationManager.AppSettings["ShowWinMessage"]);
        Log lg = new Log();
        object olock = new object();
        //TcpCli cli = new TcpCli();
        List<TcpCli> CliList = new List<TcpCli>();
        List<IPAddress> _LocalIPs = null;
        List<IPAddress> LocalIPs
        {
            get
            {
                if (_LocalIPs == null)
                {
                    _LocalIPs = new List<IPAddress>();
                    //设置地址框中的IP和端口
                    string localHostName = Dns.GetHostName();//获得主机名
                    IPHostEntry localHosEnt;
                    localHosEnt = Dns.GetHostEntry(localHostName);//根据主机名获取主机信息
                    for (int i = 0; i < localHosEnt.AddressList.Length; i++)
                    {
                        if (localHosEnt.AddressList[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                        {
                            _LocalIPs.Add(localHosEnt.AddressList[i]);
                        }
                    }
                }
                return _LocalIPs;
            }
        }
        protected int SimulateClientCount
        {
            get { return int.Parse(this.tbxClientCount.Text.Trim()); }
        }

        #region             SetText 委托的实现
        //声明委托：用于跨越线程设置文本框的内容
        public delegate void SetTextControlCallBack(string text, int type, bool appendOrSet, Control control);
        //使能控件
        public delegate void SetControlEnableCallBack(Control control, bool isEnable);
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 设置控件内容
        /// </summary>
        /// <param name="text">字符串</param>
        /// <param name="type">文本框的类型0--Control，1--TextBox</param>
        /// <param name="appendOrSet">是追加还是赋值 true-表示追加  false-表示赋值</param>
        /// <param name="control">控件</param>
        ///-----------------------------------------------------------------*
        private void SetTextControl(string text,
            int type, bool appendOrSet, Control control)
        {
            //如果调用方位于创建该控件线程以外的线程时，需要获取是否要调用Invoke方法
            if (control.InvokeRequired)
            {
                SetTextControlCallBack setTextCallBack = new SetTextControlCallBack(SetTextControl);
                control.Invoke(setTextCallBack, new object[] { text, type, appendOrSet, control });
            }
            else //如果不是线程外的调用时：设置文本框的值
            {
                if (appendOrSet == true)
                {
                    control.Text += text;
                }
                else
                {
                    control.Text = text;
                }
                if (type == 0)
                {
                    control.Text = "";
                    control.Text = text;
                }
                else if (type == 1)
                {
                    control.Text += "\r\n";
                    //设置滚动位置
                    ((TextBox)control).SelectionStart = ((TextBox)control).TextLength;
                    ((TextBox)control).ScrollToCaret();//滚动到当前光标位置
                    ((TextBox)control).SelectionLength = 0;

                }
                control.Refresh();
            }
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 使能控件
        /// </summary>
        /// <param name="control"></param>
        /// <param name="isEnable"></param>
        ///-----------------------------------------------------------------*
        private void SetControlEnable( Control control,bool isEnable)
        {
            //如果调用方位于创建该控件线程以外的线程时，需要获取是否要调用Invoke方法
            if (control.InvokeRequired)
            {
                SetControlEnableCallBack SetControlEnableCallBack = new SetControlEnableCallBack(SetControlEnable);
                control.Invoke(SetControlEnableCallBack, new object[] { control, isEnable });
            }
            else //如果不是线程外的调用时：设置文本框的值
            {
                control.Enabled = isEnable;
            }
        }
        #endregion
        /// <summary>
        /// 初始化窗体，添加事件
        /// </summary>
        ///-----------------------------------------------------------------*
        public FormTcpClientSimulator()
        {
            InitializeComponent();

            int SvrPort;string SvrIP;
            SvrIP = Data.GetServerIP(out SvrPort);
            if (SvrIP == "")
            {
                this.textBoxSrvIP.Text = LocalIPs[0].ToString();
                this.textBoxSrvPort.Text = "1238";
            }
            else
            {
                this.textBoxSrvIP.Text = SvrIP;
                this.textBoxSrvPort.Text = SvrPort.ToString();
            }
        }
        private void EnsureClients()
        {
            if (CliList.Count > 0)
            {
                for (int h = 0; h < CliList.Count; h++)
                {
                    if (CliList[h].IsConnected)
                    {
                        CliList[h].Close();//关闭一个Client                        
                    }
                }
                CliList.Clear();//清空
            }

            //for (int i = 0; i < SimulateClientCount && i < LocalIPs.Count; i++)
            for (int i = 0; i < SimulateClientCount ; i++)
            {
                TcpCli cli = new TcpCli();
                cli.Resovlver = new DatagramResolver("##");
                cli.ReceivedDatagram += new NetEvent(this.RecvData);
                cli.DisConnectedServer += new NetEvent(this.ClientClose);
                cli.ConnectedServer += new NetEvent(this.ClientConn);
                CliList.Add(cli);
            }
        }
        private IPAddress GetNextIP(List<IPAddress> LocalIPs, int index)
        {
            int count = LocalIPs.Count;
            int idx = index % count;
            return LocalIPs[idx];
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 连接到服务器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        private void buttonConn_Click(object sender, EventArgs e)
        {
            string srvIP = this.textBoxSrvIP.Text.ToLower();
            string srvPort = this.textBoxSrvPort.Text.ToLower();
            try
            {
                if (srvIP != "" && srvPort != "")
                {
                   
                     EnsureClients();//创建client连接列表
                    
                    IList<int> UseablePort = Port.GetAvailablePorts(CliList.Count);
                    for (int i = 0; i < CliList.Count; i++)
                    {
                        TcpCli cli = CliList[i];
                       
                        //IPEndPoint ieep = new IPEndPoint(IPAddress.Parse(LocalIPs[i].ToString()), UseablePort[i]);

                        if (cli.IsConnected == false)
                        {
                           // cli.Connect(srvIP, int.Parse(srvPort), ieep);
                           // Thread.Sleep(100);
                         
                            CliSocketParam param = new CliSocketParam();
                            param.TcpCli = cli;
                            param.SrvIP = srvIP;
                            param.SrvPort = int.Parse(srvPort);
                           // param.LocalIP = LocalIPs[i].ToString();
                            param.LocalIP = GetNextIP(LocalIPs, i).ToString();
                            param.LocalPort = UseablePort[i];
                            WaitCallback call = new WaitCallback((object p)=>{ 
                                CliConnSrv((CliSocketParam)p); 
                            });//创建连接的委托实例
                            ThreadPool.QueueUserWorkItem(call,param);
                        }
                        //if (cli.IsConnected == true)
                        //{
                        //    SetTextControl("TCP" + i + "已连接", 0, true, this.labelState);
                        //}
                        //else
                        //{
                        //    SetTextControl("TCP" + i + "连接失败", 0, true, this.labelState);
                        //}
                    }
                }
                else
                {
                    SetTextControl("命令错误", 0, true, this.labelState);
                }
            }
            catch
            {
                SetTextControl("服务器无相应", 0, true, this.labelState);
            }
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 关闭连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        private void buttonClose_Click(object sender, EventArgs e)
        {
            try
            {
                for (int i = 0; i < CliList.Count; i++)
                {
                    TcpCli cli = CliList[i];
                    if (cli.IsConnected == true)
                    {
                        cli.Close();
                       
                        SetControlEnable(this.textBoxSrvIP, true);
                        SetControlEnable(this.textBoxSrvPort, true);
                        SetControlEnable(this.buttonConn, true);//显示连接按钮
                        SetControlEnable(this.buttonClose, false);//不显示关闭按钮
                        SetTextControl(i+"连接已关闭", 0, true, this.labelState);

                    }
                    //else
                    //{
                    //    SetTextControl(i+"未连接到服务器", 0, true, this.labelState);
                    //}
                }
            }
            catch
            {
                SetTextControl("当前无连接", 0, true, this.labelState);
            }
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        private void buttonSndData_Click(object sender, EventArgs e)
        {
            //加上结束标志##
           // string dataToSnd = this.textBoxSndData.Text.ToLower()+"##";
            string dataToSnd = this.textBoxSndData.Text.Trim();
            try
            {
                for (int i = 0; i < CliList.Count; i++)
                {
                    TcpCli cli = CliList[i];
                    string ip = "";
                    if (cli.IsConnected == true)
                    {
                        ip = ((IPEndPoint)cli.ClientSession.ClientSocket.LocalEndPoint).Address.ToString();
                        //数据转换
                        Byte[] data = Convert2ByteArrayFromHexString(ip, dataToSnd, this.chxSimClient.Checked);
                        //int[] ary = Array.ConvertAll<Byte, Int32>(data, delegate(byte n) { return (int)n; });
                        //string str = Data.ToString(ary, " ", "{0:X}");
                       // lg.log(str);
                        //cli.Send(data); //发送数据
                        //SetTextControl(i+"已发送数据", 0, true, this.labelState);

                        CliSendDataParam param = new CliSendDataParam();
                        param.Data = data;
                        param.TcpCli = cli;
                        WaitCallback call = new WaitCallback((object p) => { CliSendData((CliSendDataParam)p); });//创建连接的委托实例

                        ThreadPool.QueueUserWorkItem(call, param);//寻一个线程，完成发送
                        if (ShowWinMessage)
                        {
                            SetTextControl(i + "已发送数据", 0, true, this.labelState);
                        }
                        //CliSendData
                        //Thread.Sleep(1000);
                    }
                    else
                    {
                        SetTextControl(i + "未连接到服务器", 0, true, this.labelState);
                    }
                }
            }
            catch
            {
                SetTextControl("服务器主动拒绝访问", 0, true, this.labelState);
            }

        }
        private byte[] Convert2ByteArrayFromHexString(string ClientIP,string input,bool IsSimClient)
        {
            string[] arr = input.Trim().Split(' ');
            byte[] data = new byte[arr.Length];
            for (int i = 0; i < arr.Length; i++)
            {
                data[i] = (Byte)Convert.ToInt32(arr[i], 16);
            }
            if (IsSimClient)
            {
               // string ip  = ((IPEndPoint)tcpCli.ClientSession.ClientSocket.LocalEndPoint).Address.ToString();

                string simCode = Data.GetSimCodeFromXml(xDocCfg,ClientIP);
                if (ShowWinMessage)
                {
                    SetTextControl(ClientIP + " " + simCode + "\n", 1, true, this.textBoxFeedBack);
                }
                    if (simCode != "")
                    {
                        for (int k = 67; k < 67 + 11; k++)
                        {
                            data[k] = (byte)simCode[k - 67];
                        }
                    }
                    string checkSumStr = GetCheckSumResultStr(data);

                    data[78] = (Byte)Convert.ToInt32(checkSumStr.Substring(0, 2), 16);//重算校验和，高位
                    data[79] = (Byte)Convert.ToInt32(checkSumStr.Substring(2, 2), 16);//重算校验和，低位
               
                    
            }
            return data;
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 退出程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        private void buttonExit_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < CliList.Count; i++)
            {
                TcpCli cli = CliList[i];
                if (cli.IsConnected == true)
                {
                    //清理资源
                    cli.Close();
                }
            }
            this.Dispose();
            this.Close();
            this.ThreadPool.Stop(true);
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 清空数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        private void buttonClearData_Click(object sender, EventArgs e)
        {
            this.textBoxSndData.Text = "";
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 清空发回信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        private void buttonClearIfo_Click(object sender, EventArgs e)
        {
            this.textBoxFeedBack.Text = "";
        }
        private void btnChecksum_Click(object sender, EventArgs e)
        {
            string dataToSnd = this.textBoxSndData.Text.Trim();
            if (dataToSnd.Length > 8)
            {
                Byte[] data = Convert2ByteArrayFromHexString("",dataToSnd,false);              
    
                tbChecksum.Text = GetCheckSumResultStr(data);
            }
           
        }

        private string GetCheckSumResultStr(Byte[] data)
        {
            int dataLen = data[1] * 256 + data[2];//数据长度(第1,2字节)
            ushort checkSumVal = GetCheckSum(data, 3, dataLen);
            return Convert.ToString(checkSumVal, 16).ToUpper();
        }
        /// <summary>
        /// 求字节数组中startIndex到endIndex之间（包含边界)的校验和 -- 双字节无符号数；
        /// </summary>
        /// <param name="BomsPackByteArray"></param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        /// <returns></returns>
        private ushort GetCheckSum(Byte[] BomsPackByteArray, int startIndex, int length)
        {
            //Byte[] data = Convert2ByteArrayFromHexString(dataToSnd);
            long sum = 0;
            //遍历数据0~n 求和
            //for (int i = 3; i < BomsPackByteArray.Length - 5; i++)
            for (int i = startIndex; i < startIndex + length; i++)
            {
                sum += BomsPackByteArray[i];
            }
            long checkSum = (~(sum & (256 * 256 - 1))) + 1;
            ushort checkSumVal = (ushort)checkSum;
            return checkSumVal;// Convert.ToString(checkSumVal, 16);
        }
        #region 定义TCP客户端事件
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 客户端连接事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        void ClientConn(object sender, NetEventArgs e)
        {
            if (ShowWinMessage)
            {
                string info = string.Format("A Client:{0} connect server :{1}", e.Client,
                e.Client.ClientSocket.RemoteEndPoint.ToString());
                SetTextControl(info, 1, true, this.textBoxFeedBack);
                SetTextControl("请求连接成功", 0, true, this.labelState);
                
            }
            SetControlEnable(this.textBoxSrvIP, false);
            SetControlEnable(this.textBoxSrvPort, false);
            SetControlEnable(this.buttonConn, false);
            SetControlEnable(this.buttonClose, true);
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 客户端关闭事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        void ClientClose(object sender, NetEventArgs e)
        {
           
            TcpCli cli = FindClient(e.Client);
            if (cli != null)
            {
                cli.Close();
                if (ShowWinMessage)
                {
                    string info;

                    if (e.Client.TypeOfExit == Session.ExitType.ExceptionExit)
                    {
                        info = string.Format("A Client Session:{0} Exception Closed.", e.Client.ID);
                    }
                    else
                    {
                        info = string.Format("A Client Session:{0} Normal Closed.", e.Client.ID);
                    }
                    SetTextControl(info, 1, true, this.textBoxFeedBack);
                   
                }
                SetControlEnable(this.buttonConn, true);
            }
           
        }
        ///-----------------------------------------------------------------*
        /// <summary>
        /// 收到数据事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///-----------------------------------------------------------------*
        void RecvData(object sender, NetEventArgs e)
        {
           // string rcvData = e.Client.Datagram;
            //string dataToShow = rcvData.Substring(0,rcvData.Length-2);
            //string info = string.Format("recv data:{0} from:{1}.", dataToShow, e.Client);
            if( e.Client.ByteArrayList.Count>0 &&  e.Client.ByteArrayList[0]!=null)
            {
                //string info = e.Client.ByteArrayList[0].HexArray.ToString(" ","{0:X}");
                string info = Data.byteToHexStr(e.Client.ByteArrayList[0].HexArray, true);
                if (ShowWinMessage)
                {
                    SetTextControl(info, 1, true, this.textBoxFeedBack);
                }
            }
        }

        #endregion

        TcpCli FindClient(Session session)
        {
            TcpCli Cli = CliList.Find(cl => cl.ClientSession == session);
            return Cli;
        }

        protected void CliConnSrv(CliSocketParam cliSocketParam)
        {
            if(cliSocketParam!=null)
            {
                TcpCli cli = cliSocketParam.TcpCli;
                cli.Connect(cliSocketParam.SrvIP, cliSocketParam.SrvPort, new IPEndPoint(IPAddress.Parse(cliSocketParam.LocalIP), cliSocketParam.LocalPort));
            }
            
        }
        protected void CliSendData(CliSendDataParam sendDataParam)
        {
            TcpCli cli = sendDataParam.TcpCli;
            if (cli.IsConnected)
            {
                cli.Send(sendDataParam.Data);
            }
        }
    }
}
